<template>
    <w-dialog v-if="pcMode" :border="false" closeFree width="600px" @ok="selectOk" :title="title" v-model="visible">
        <div class="picker" v-if="visible">
            <div class="candidate" v-loading="loading">
                <div v-if="type !== 'role'">
                    <el-input v-model="search" @input="searchUser" style="width: 95%" clearable placeholder="搜索人员，支持拼音、姓名" :prefix-icon="Search"/>
                    <div v-show="!showUsers">
                        <ellipsis hoverTip style="height: 18px; color: #8c8c8c; padding: 5px 0 0" :row="1" :content="deptStackStr">
                            <template #pre>
                                <el-icon>
                                    <OfficeBuilding/>
                                </el-icon>
                            </template>
                        </ellipsis>
                        <div style="margin-top: 5px">
                            <el-checkbox v-model="checkAll" @change="handleCheckAllChange" :disabled="!multiple">全选</el-checkbox>
                            <span v-show="deptStack.length > 0" class="top-dept" @click="beforeNode">上一级</span>
                        </div>
                    </div>
                </div>
                <div class="role-header" v-else>
                    <div>系统角色</div>
                </div>
                <div class="org-items" :style="type === 'role' ? 'height: 350px' : ''">
                    <el-empty :image-size="100" description="似乎没有数据" v-show="orgs.length === 0"/>
                    <div v-for="(org, index) in orgs" :key="index" :class="orgItemClass(org)" @click="selectChange(org)">
                        <el-checkbox v-model="org.selected" :disabled="disableDept(org)"></el-checkbox>
                        <div v-if="org.type === 'dept'">
                            <el-icon>
                                <FolderOpened/>
                            </el-icon>
                            <span class="name">{{ org.name }}</span>
                            <span @click.stop="nextNode(org)" :class="`next-dept${org.selected ? '-disable' : ''}`">
                <branch-one theme="outline"/>下级
              </span>
                        </div>
                        <div v-else-if="org.type === 'user'">
                            <avatar :size="35" :name="org.name" :status="org.isLeader ? 'leader' : ''" :src="org.avatar"/>
                        </div>
                        <div style="display: inline-block" v-else>
                            <icon name="iconfont icon-bumen"></icon>
                            <span class="name">{{ org.name }}</span>
                        </div>
                    </div>
                </div>
            </div>
            <div class="selected">
                <div class="count">
                    <span>已选 {{ select.length }} 项</span>
                    <span @click="clearSelected">清空</span>
                </div>
                <div class="org-items" style="height: 350px">
                    <el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="select.length === 0"/>
                    <div v-for="(org, index) in select" :key="index" :class="orgItemClass(org)">
                        <div v-if="org.type === 'dept'">
                            <el-icon>
                                <FolderOpened/>
                            </el-icon>
                            <span style="position: static" class="name">{{ org.name }}</span>
                        </div>
                        <div v-else-if="org.type === 'user'" style="display: flex; align-items: center">
                            <avatar :size="35" :name="org.name" :src="org.avatar"/>
                        </div>
                        <div v-else>
                            <card-two theme="outline"/>
                            <span class="name">{{ org.name }}</span>
                        </div>
                        <el-icon @click="noSelected(index)">
                            <Close/>
                        </el-icon>
                    </div>
                </div>
            </div>
        </div>
    </w-dialog>
    <popup v-else v-model:show="visible" :style="popupStyle" position="left" lazy-render safe-area-inset-bottom>
        <nav-bar :title="title" placeholder left-text="返回" right-text="确定" left-arrow @click-left="close" @click-right="selectOk"/>
        <div class="mobile-picker">
            <div style="padding: 15px">
                <el-input v-model="search" @input="searchUser" clearable :prefix-icon="Search" placeholder="搜索人员，支持拼音、姓名"></el-input>
            </div>
            <cell class="m-org-item m-org-item-tab" v-if="type !== 'role'">
                <template #title>
                    <checkbox shape="square" :disabled="!multiple" @change="handleCheckAllChange" v-model="checkAll">
                        全选
                        <span style="margin: 0 10px; color: #8c8c8c">已选 [ {{ select.length }} ]</span>
                        <span v-show="select.length > 0 && multiple" style="color: #3971f8" @click.stop="clearSelected">清空</span>
                    </checkbox>
                </template>
                <template #right-icon v-if="deptStack.length > 0">
                    <div @click="beforeNode" class="to-top">上一级</div>
                </template>
            </cell>
            <list v-model="loading" finished error-text="请求失败，点击重新加载">
                <cell class="m-org-item" v-for="org in nodes" :key="org.id">
                    <template #title>
                        <div @click="selectChange(org)">
                            <checkbox v-model="org.selected" :disabled="disableDept(org)">
                                <avatar :name="org.name" :src="org.avatar" v-if="org.type === 'user'"></avatar>
                                <span v-else>{{ org.name }}</span>
                            </checkbox>
                        </div>
                    </template>
                    <template #right-icon v-if="org.type === 'dept'">
                        <div @click.stop="nextNode(org)" :class="{'m-org-item-next': true, 'm-org-item-next-disabled': org.selected}">
                            <branch-one theme="outline"/>
                            <span> 下级</span>
                        </div>
                    </template>
                </cell>
            </list>
        </div>
    </popup>
</template>

<script>
import {computed, reactive, toRefs} from 'vue'
import {Popup, List, Cell, NavBar, Radio, Checkbox, Dialog, showFailToast} from 'vant'
import {ElMessage, ElMessageBox} from 'element-plus'
import {Search, FolderOpened, OfficeBuilding, Close} from '@element-plus/icons-vue'
import {BranchOne, CardTwo} from '@icon-park/vue-next'
import {getComponentTree} from '/@/api/sys/dept'
import {getComponentUsers} from '/@/api/sys/user'

export default {
    name: 'OrgPicker',
    components: {
        Popup,
        List,
        Cell,
        NavBar,
        Radio,
        Checkbox,
        FolderOpened,
        OfficeBuilding,
        BranchOne,
        Close,
        CardTwo
    },
    props: {
        pcMode: {
            default: true,
            type: Boolean
        },
        title: {
            default: '请选择',
            type: String
        },
        type: {
            default: 'org', //org选择部门/人员  user-选人  dept-选部门 role-选角色
            type: String
        },
        multiple: {
            //是否多选
            default: false,
            type: Boolean
        },
        selected: {
            default: () => {
                return []
            },
            type: Array
        }
    },
    emits: ['ok', 'close'],
    setup(props, context) {
        const {pcMode, multiple, type, selected} = toRefs(props)
        const state = reactive({
            visible: false,
            loading: false,
            checkAll: false,
            nowDeptId: null,
            isIndeterminate: false,
            searchUsers: [],
            nodes: [],
            select: [],
            search: '',
            deptStack: [],
            popupStyle: {
                height: '100%',
                width: '100%',
                background: '#f7f7f9'
            },
            type: ''
        })
        const deptStackStr = computed(() => {
            return String(state.deptStack.map((v) => v.name)).replaceAll(',', ' > ')
        })
        const orgs = computed(() => {
            return !state.search || state.search.trim() === ''
                ? state.nodes
                : state.searchUsers
        })
        const showUsers = computed(() => {
            return state.search || state.search.trim() !== ''
        })
        const show = () => {
            state.visible = true
            state.type = type.value
            setTimeout(() => {
                init()
                getOrgList()
            }, 100)
        }
        const orgItemClass = (org) => {
            return {
                'org-item': true,
                'org-dept-item': org.type === 'dept',
                'org-user-item': org.type === 'user',
                'org-role-item': org.type === 'role'
            }
        }
        const disableDept = node => {
            return state.type === 'user' && 'dept' === node.type
        }
        const getOrgList = () => {
            state.loading = true
            getComponentTree({
                deptId: state.nowDeptId,
                type: state.type === 'org' ? 'user' : state.type
            }).then((rsp) => {
                state.loading = false
                state.nodes = rsp.data
                selectToLeft()
            }).catch((err) => {
                state.loading = false
                ElMessage.error(err.data.message || '获取数据失败')
            })
        }
        const getShortName = name => {
            if (name) {
                return name.length > 2 ? name.substring(1, 3) : name
            }
            return '**'
        }
        const searchUser = () => {
            let userName = state.search.trim()
            state.searchUsers = []
            state.loading = true
            getComponentUsers(userName).then((rsp) => {
                state.loading = false
                state.searchUsers = rsp.data
                selectToLeft()
            }).catch((err) => {
                state.loading = false
                ElMessage.error(err.data.message || '获取用户信息失败')
            })
        }
        const selectToLeft = () => {
            let nodes = state.search.trim() === '' ? state.nodes : state.searchUsers
            nodes.forEach((node) => {
                for (let i = 0; i < state.select.length; i++) {
                    if (state.select[i].id === node.id) {
                        node.selected = true
                        break
                    } else {
                        node.selected = false
                    }
                }
            })
        }
        const selectChange = (node) => {
            if (pcMode.value ? node.selected : !node.selected) {
                state.checkAll = false
                for (let i = 0; i < state.select.length; i++) {
                    if (state.select[i].id === node.id) {
                        state.select.splice(i, 1)
                        break
                    }
                }
                node.selected = false
            } else if (!disableDept(node)) {
                node.selected = true
                let nodes = state.search.trim() === '' ? state.nodes : state.searchUsers
                if (!multiple.value) {
                    nodes.forEach((nd) => {
                        if (node.id !== nd.id) {
                            nd.selected = false
                        }
                    })
                }
                if (node.type === 'dept') {
                    if (!multiple.value) {
                        state.select = [node]
                    } else {
                        state.select.unshift(node)
                    }
                } else {
                    if (!multiple.value) {
                        state.select = [node]
                    } else {
                        state.select.push(node)
                    }
                }
            }
        }
        const noSelected = (index) => {
            let nodes = state.nodes
            for (let f = 0; f < 2; f++) {
                for (let i = 0; i < nodes.length; i++) {
                    if (nodes[i].id === state.select[index].id) {
                        nodes[i].selected = false
                        state.checkAll = false
                        break
                    }
                }
                nodes = state.searchUsers
            }
            state.select.splice(index, 1)
        }
        const handleCheckAllChange = () => {
            state.nodes.forEach((node) => {
                if (state.checkAll) {
                    if (!node.selected && !disableDept(node)) {
                        node.selected = true
                        state.select.push(node)
                    }
                } else {
                    node.selected = false
                    for (let i = 0; i < state.select.length; i++) {
                        if (state.select[i].id === node.id) {
                            state.select.splice(i, 1)
                            break
                        }
                    }
                }
            })
        }
        const nextNode = (node) => {
            if (!node.selected) {
                state.nowDeptId = node.id
                state.deptStack.push(node)
                getOrgList()
            }
        }
        const beforeNode = () => {
            if (state.deptStack.length === 0) {
                return
            }
            if (state.deptStack.length < 2) {
                state.nowDeptId = null
            } else {
                state.nowDeptId = state.deptStack[state.deptStack.length - 2].id
            }
            state.deptStack.splice(state.deptStack.length - 1, 1)
            getOrgList()
        }
        const recover = () => {
            state.select = []
            state.nodes.forEach((nd) => (nd.selected = false))
        }
        const selectOk = () => {
            if (state.select && state.select.length === 0) {
                if (pcMode.value) {
                    ElMessage.warning('选择的项为空')
                } else {
                    showFailToast('所选为空')
                }
                return
            }
            context.emit('ok', Object.assign([], state.select))
            state.visible = false
            recover()
        }
        const clearSelected = () => {
            if (pcMode.value) {
                ElMessageBox.confirm('您确定要清空已选中的项?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    state.checkAll = false
                    recover()
                })
            } else {
                Dialog.confirm({
                    title: '提示',
                    message: '您确定要清空已选项吗？'
                }).then(() => {
                    state.checkAll = false
                    recover()
                })
            }
        }
        const close = () => {
            context.emit('close')
            state.visible = false
            recover()
        }
        const init = () => {
            state.checkAll = false
            state.nowDeptId = null
            state.nodes = []
            state.deptStack = []
            state.select = Object.assign([], selected.value)
            selectToLeft()
        }
        return {
            ...toRefs(state),
            deptStackStr,
            orgs,
            showUsers,
            show,
            selectChange,
            handleCheckAllChange,
            disableDept,
            nextNode,
            beforeNode,
            selectOk,
            clearSelected,
            close,
            searchUser,
            noSelected,
            getShortName,
            orgItemClass,
            Search
        }
    }
}
</script>

<style lang="scss" scoped>
$containWidth: 278px;

.candidate,
.selected {
    position: absolute;
    display: inline-block;
    width: $containWidth;
    height: 400px;
    border: 1px solid #e8e8e8;
}

.picker {
    height: 402px;
    position: relative;
    text-align: left;

    .candidate {
        left: 0;
        top: 0;

        .role-header {
            padding: 10px !important;
            margin-bottom: 5px;
            border-bottom: 1px solid #e8e8e8;
        }

        .top-dept {
            margin-left: 20px;
            cursor: pointer;
            color: var(--el-color-primary);
        }

        .next-dept {
            float: right;
            color: var(--el-color-primary);
            cursor: pointer;
        }

        .next-dept-disable {
            float: right;
            color: #8c8c8c;
            cursor: not-allowed;
        }

        & > div:first-child {
            padding: 5px 10px;
        }
    }

    .selected {
        right: 0;
        top: 0;
    }

    .org-items {
        overflow-y: auto;
        height: 310px;

        .el-icon-close {
            position: absolute;
            right: 5px;
            cursor: pointer;
            font-size: larger;
        }

        .org-dept-item {
            padding: 5px 5px;

            & > div {
                display: inline-block;

                & > span:last-child {
                    position: absolute;
                    right: 5px;
                }
            }
        }

        .org-role-item {
            display: flex;
            align-items: center;
            padding: 10px 5px;
        }

        .org-user-item {
            display: flex;
            align-items: center;
            padding: 5px 5px;
        }

        :deep(.org-item) {
            margin: 0 5px;
            border-radius: 5px;
            position: relative;
            display: flex;
            align-items: center;

            .el-checkbox {
                margin-right: 10px;
            }

            .name {
                margin-left: 5px;
            }

            &:hover {
                background: #f1f1f1;
            }
        }
    }
}

.selected {
    border-left: none;

    .count {
        width: calc($containWidth - 20px);
        padding: 10px;
        display: inline-block;
        border-bottom: 1px solid #e8e8e8;
        margin-bottom: 5px;

        & > span:nth-child(2) {
            float: right;
            color: #c75450;
            cursor: pointer;
        }
    }
}

:deep(.el-dialog__body) {
    padding: 10px 20px;
}

.disabled {
    cursor: not-allowed !important;
    color: #8c8c8c !important;
}

.mobile-picker {
    :deep(.el-input) {
        border-radius: 10px;

        :deep(.icon) {
            font-size: 1.2rem;
        }

        .el-input__inner {
            border: none;
            border-radius: 5px;
            font-size: 1rem;
        }
    }

    .m-org-item-tab {
        margin-bottom: 10px;
        color: var(--el-color-primary);
    }

    .m-org-item {
        color: #303133;
        font-size: 1.1rem !important;
        padding: 15px 15px !important;
        border-bottom: 1px solid var(--next-aside-bgc);

        .m-org-item-next {
            cursor: pointer;
            color: var(--el-color-primary);
            font-size: 1.1rem;
        }

        .m-org-item-next-disabled {
            cursor: not-allowed;
            color: #c8c8c8;
        }

        :deep(.icon) {
            font-size: 1.1rem;
        }

        .to-top {
            cursor: pointer;
            color: var(--el-color-primary);
        }
    }
}

::-webkit-scrollbar {
    float: right;
    width: 4px;
    height: 4px;
    background-color: white;
}

::-webkit-scrollbar-thumb {
    border-radius: 16px;
    background-color: #efefef;
}
</style>
